from typing import Dict, Any, Optional
import json

from constants import consts as consts


class WebHook:
    """
    解析 Gitee 钩子数据的通用类，支持公共字段和动态扩展字段。
    Gitee钩子对象数据格式参考：https://gitee.com/help/articles/4271#article-header1
    """

    def __init__(self, data: Dict[str, Any]):
        # 公共字段（直接提取）
        self.hook_id: str = data.get("hook_id")
        self.hook_url: str = data.get("hook_url")
        self.hook_name: str = data.get("hook_name")
        self.password: str = data.get("password")
        self.timestamp: int = data.get("timestamp")
        self.sign: str = data.get("sign")

        # 公共但可能为空的字段
        self.repository: Optional[Dict] = data.get("repository")
        self.project: Optional[Dict] = data.get("project")
        self.enterprise: Optional[Dict] = data.get("enterprise")

        # 用户相关字段（统一为 `sender`）
        self.sender: Dict = data.get("sender")  # 触发者信息

        # 差异字段（动态存储）
        self.extra_data: Dict[str, Any] = {}
        self._parse_dynamic_fields(data)

        # 常用字段
        self._pr_number = None
        self._branch = None
        self._comment = None
        self._commenter = None
        self._assignees = None
        self._repo_owner = None
        self._repo_name = None
        self._pull_request = None

    @property
    def pull_request(self):
        if self._pull_request:
            return self._pull_request
        self._pull_request = self.get("pull_request", {})
        return self._pull_request

    @property
    def pr_number(self):
        if self._pr_number:
            return self._pr_number
        self._pr_number = self.pull_request.get('number')
        return self._pr_number

    @property
    def branch(self):
        if self._branch:
            return self._branch
        self._branch = self.pull_request.get('base', {}).get('ref')
        return self._branch

    @property
    def repo_owner(self):
        if self._repo_owner:
            return self._repo_owner
        self._repo_owner = self.pull_request.get('base', {}).get('repo', {}).get('owner', {}).get('name')
        return self._repo_owner

    @property
    def repo_name(self):
        if self._repo_name:
            return self._repo_name
        self._repo_name = self.pull_request.get('base', {}).get('repo', {}).get('name')
        return self._repo_name

    @property
    def comment(self):
        if self._comment:
            return self._comment
        self._comment = self.get("comment", {})
        return self._comment

    @property
    def commenter(self):
        if self._commenter:
            return self._commenter
        self._commenter = self.comment.get('user', {}).get('html_url')
        return self._commenter

    @property
    def assignees(self):
        if self._assignees:
            return self._assignees
        self._assignees = self.get('target_user', {}).get('html_url')
        return self._assignees

    @property
    def comment_body(self):
        return self.comment.get('body', '').lower()

    def _parse_dynamic_fields(self, data: Dict[str, Any]) -> None:
        """提取非公共字段到 `extra_data` 字典"""
        for key, value in data.items():
            if key not in consts.PUBLIC_FIELDS:
                self.extra_data[key] = value

    def get(self, key: str, default: Any = None) -> Any:
        """安全获取动态字段"""
        return self.extra_data.get(key, default)

    def to_json(self) -> Dict[str, Any]:
        """转换为字典格式（用于序列化）"""
        return {
            "hook_id": self.hook_id,
            "hook_url": self.hook_url,
            "hook_name": self.hook_name,
            "password": self.password,
            "timestamp": self.timestamp,
            "sign": self.sign,
            "repository": self.repository,
            "project": self.project,
            "enterprise": self.enterprise,
            "sender": self.sender,
            **self.extra_data
        }

    @classmethod
    def from_json(cls, json_str: str) -> 'WebHook':
        """从 JSON 字符串解析"""
        data = json.loads(json_str)
        return cls(data)

    def __getattr__(self, name: str) -> Any:
        """动态访问差异字段（例如：data.action）"""
        if name in self.extra_data:
            return self.extra_data[name]
        raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
